#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# 获取对象信息
# 1、使用type()：判断对象类型
# 基本类型：
import types
print(type(123))
print(type('str'))
print(type(None))
print(type(abs))  # 变量指向函数
print(type(123) == type(345))
print(type(123) == int)
print(type('abc'))
print(type(123) == type('abc'))
print('=========分割线==========')
# 判断一个对象是否是函数
def fn():
    pass
print(type(fn) == types.FunctionType)
print(type(abs) == types.BuiltinFunctionType)
print(type(lambda x: x) == types.LambdaType)
print(type(x for x in range(10)) == types.GeneratorType)
print('=========分割线==========')
# 2、使用isinstance()：判断class的类型
class Animal(object):
    def run(self):
        print("Animal is running...")
class Dog(Animal):
    def run(self):
        print('DOG IS RUNNING')
    def eat(self):
        print('EATING Meat...')
class Cat(Animal):
    def run(self):
        print('CAT IS RUNNING')
a = Animal()
d = Dog()
c = Cat()
print(isinstance(d, Dog))
print(isinstance(d, Animal))
print(isinstance(a, Dog))
# 能用type()判断的基本类型也可以用isinstance()判断：
print(isinstance('a', str))
print(isinstance(123, int))
print(isinstance(b'abc', bytes))
# 还可以判断一个变量是否是某些类型中的一种，比如下面的代码就可以判断是否是list或者tuple：
print(isinstance([1, 2, 3], list))
print(isinstance([1, 2, 3], tuple))
print(isinstance((1, 2, 3), tuple))
# 总是优先使用isinstance()判断类型，可以将指定类型及其子类“一网打尽”。

# 3、使用dir()：获得一个对象的所有属性和方法，返回一个包含字符串的list
print(dir('ABC'))
# 类似__xxx__的属性和方法在Python中都是有特殊用途的，比如__len__方法返回长度。在Python中，如果你调用len()函数试图获取一个对象的长度，实际上，在len()函数内部，它自动去调用该对象的__len__()方法，所以，下面的代码是等价的：
# 剩下的都是普通属性或方法，比如lower()返回小写的字符串：
print(len('abcdefghijklmnopqrstuvwxyz'))
print('abcdefghijklmnopqrstuvwxyz'.__len__())
print('abcdefghijklmnopqrstuvwxyz'.upper())
print('=========分割线==========')
# 仅仅把属性和方法列出来是不够的，配合getattr()、setattr()以及hasattr()，我们可以直接操作一个对象的状态：
class MyObject(object):
    def __init__(self):
        self.x = 9

    def power(self):
        return self.x*self.x
obj = MyObject()
# 测试：
print(hasattr(obj, 'x'))  # 有属性'x'吗？
print(obj.x)
print(hasattr(obj, 'y'))  # 有属性'y'吗？
setattr(obj, 'y', 200)  # 设置一个属性'y'
print(hasattr(obj, 'y'))  # 有属性'y'吗？
print(getattr(obj, 'y'))  # 获取属性'y'
print(getattr(obj, 'z', 404))  # 获取属性'z'，如果不存在，返回默认值404

print(hasattr(obj, 'power'))  # 有属性'power'吗？
print(getattr(obj, 'power'))  # 获取属性'power'
fn = getattr(obj, 'power')  # 获取属性'power'并赋值到变量fn
print(fn)  # fn指向obj.power
print(fn())  # 调用fn()与调用obj.power()是一样的

#通过内置的一系列函数，我们可以对任意一个Python对象进行剖析，拿到其内部的数据。要注意的是，只有在不知道对象信息的时候，我们才会去获取对象信息
'''
如果可以直接写：
sum = obj.x + obj.y
就不要写：
sum = getattr(obj, 'x') + getattr(obj, 'y')
一个正确的用法的例子如下：
def readImage(fp):
    if hasattr(fp, 'read'):
        return readData(fp)
    return None
'''